react-native-jet-markdown 0.2.1 → 0.2.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (50) hide show
  1. package/README.md +4 -56
  2. package/android/src/main/cpp/JniBindings.cpp +0 -106
  3. package/android/src/main/java/com/jetmarkdown/JetMarkdownNative.kt +0 -79
  4. package/android/src/main/java/com/jetmarkdown/JetMarkdownPackage.kt +1 -2
  5. package/android/src/main/java/com/jetmarkdown/render/spans/MarkdownLineHeightSpan.kt +2 -13
  6. package/cpp/react/override/react/renderer/components/JetMarkdownViewSpec/ComponentDescriptors.h +0 -4
  7. package/cpp/tests/parser_tests.cpp +0 -402
  8. package/cpp/tests/run_tests.sh +0 -3
  9. package/lib/module/index.js +0 -2
  10. package/lib/module/index.js.map +1 -1
  11. package/lib/typescript/src/index.d.ts +1 -3
  12. package/lib/typescript/src/index.d.ts.map +1 -1
  13. package/lib/typescript/src/types.d.ts +0 -127
  14. package/lib/typescript/src/types.d.ts.map +1 -1
  15. package/package.json +2 -5
  16. package/src/index.tsx +0 -9
  17. package/src/types.ts +0 -134
  18. package/android/src/main/java/com/jetmarkdown/editor/EditorSpans.kt +0 -217
  19. package/android/src/main/java/com/jetmarkdown/editor/JetMarkdownEditorManager.kt +0 -224
  20. package/android/src/main/java/com/jetmarkdown/editor/JetMarkdownEditorView.kt +0 -1736
  21. package/cpp/core/AstToMarkdown.cpp +0 -549
  22. package/cpp/core/AstToMarkdown.h +0 -16
  23. package/cpp/core/EditorRuns.cpp +0 -640
  24. package/cpp/core/EditorRuns.h +0 -94
  25. package/cpp/core/EditorText.cpp +0 -15
  26. package/cpp/core/EditorText.h +0 -18
  27. package/cpp/react/JetMarkdownEditorShadowNode.cpp +0 -54
  28. package/cpp/react/JetMarkdownEditorShadowNode.h +0 -55
  29. package/cpp/react/JetMarkdownEditorState.h +0 -35
  30. package/ios/editor/JetMarkdownEditor.h +0 -12
  31. package/ios/editor/JetMarkdownEditor.mm +0 -2002
  32. package/lib/module/JetMarkdownEditor.js +0 -85
  33. package/lib/module/JetMarkdownEditor.js.map +0 -1
  34. package/lib/module/JetMarkdownEditor.native.js +0 -244
  35. package/lib/module/JetMarkdownEditor.native.js.map +0 -1
  36. package/lib/module/JetMarkdownEditorNativeComponent.ts +0 -173
  37. package/lib/module/useJetMarkdownEditor.js +0 -41
  38. package/lib/module/useJetMarkdownEditor.js.map +0 -1
  39. package/lib/typescript/src/JetMarkdownEditor.d.ts +0 -6
  40. package/lib/typescript/src/JetMarkdownEditor.d.ts.map +0 -1
  41. package/lib/typescript/src/JetMarkdownEditor.native.d.ts +0 -6
  42. package/lib/typescript/src/JetMarkdownEditor.native.d.ts.map +0 -1
  43. package/lib/typescript/src/JetMarkdownEditorNativeComponent.d.ts +0 -105
  44. package/lib/typescript/src/JetMarkdownEditorNativeComponent.d.ts.map +0 -1
  45. package/lib/typescript/src/useJetMarkdownEditor.d.ts +0 -36
  46. package/lib/typescript/src/useJetMarkdownEditor.d.ts.map +0 -1
  47. package/src/JetMarkdownEditor.native.tsx +0 -301
  48. package/src/JetMarkdownEditor.tsx +0 -90
  49. package/src/JetMarkdownEditorNativeComponent.ts +0 -173
  50. package/src/useJetMarkdownEditor.ts +0 -50
package/README.md CHANGED
@@ -1,9 +1,9 @@
1
1
  <p align="center">
2
- <img alt="react-native-jet-markdown — native markdown viewer and WYSIWYG editor for React Native" src="https://raw.githubusercontent.com/alizahid/react-native-jet-markdown/main/docs/hero.svg" width="900">
2
+ <img alt="react-native-jet-markdown — native markdown viewer for React Native" src="https://raw.githubusercontent.com/alizahid/react-native-jet-markdown/main/docs/hero.svg" width="900">
3
3
  </p>
4
4
 
5
5
  <p align="center">
6
- Fast, fully native Markdown viewer &amp; WYSIWYG editor for React Native
6
+ Fast, fully native Markdown viewer for React Native
7
7
  </p>
8
8
 
9
9
  <p align="center">
@@ -150,73 +150,21 @@ Numbers from the shared C++ core (Apple M-series, `-O2`; the same code runs on d
150
150
  | --- | --- | --- |
151
151
  | Parse a typical feed post | 1.5 KB mixed markdown | **35 µs** |
152
152
  | Parse a large document | 160 KB | **4.1 ms** |
153
- | Open a document in the editor (`editorFromMarkdown`) | 160 KB, ~6,400 style runs | **4.7 ms** |
154
- | Serialize the editor back to markdown | 160 KB | **5.8 ms** |
155
153
  | Serialize the full `defaultStyles` object in JS | 980 B JSON | **3 µs**, memoized |
156
154
 
157
- Beyond raw parsing: measurement runs on the Fabric layout thread (never on main), parse + layout results are cached and shared between measure and mount, editor keystrokes only rebuild the derived styling of the lines they touch, and markdown serialization is coalesced to once per frame. The 500-item Feed screen in the example app scrolls at 60 fps on both platforms.
155
+ Beyond raw parsing: measurement runs on the Fabric layout thread (never on main), and parse + layout results are cached and shared between measure and mount. The 500-item Feed screen in the example app scrolls at 60 fps on both platforms.
158
156
 
159
157
  ### Why styles cross as JSON
160
158
 
161
159
  You may notice styles ship natively as one `stylesJson` string instead of a structured object. This is deliberate, not legacy: Fabric props cross via JSI either way (there is no old-bridge serialization in either design), codegen cannot express the open-keyed `mention.variants` map, and the string doubles as the cache key shared by the C++ measurer, iOS, and Android — a structured prop would need deep equality or native re-serialization to get the same caching. The cost is ~3 µs once per distinct styles object.
162
160
 
163
- ## Editor
164
-
165
- > [!WARNING]
166
- > The editor is not ready for production use yet. The viewer (`JetMarkdownView`) is stable; `JetMarkdownEditor` still has known issues and its API may change. Track progress in the issue tracker before shipping it.
167
-
168
- `JetMarkdownEditor` is a WYSIWYG editor with markdown as the interchange format: no visible syntax while editing, `onChangeMarkdown` fires with serialized markdown on every edit, and `setValue`/`defaultValue`/paste parse markdown into styled content.
169
-
170
- ```tsx
171
- import { JetMarkdownEditor, useJetMarkdownEditor } from "react-native-jet-markdown";
172
-
173
- function Compose() {
174
- const editor = useJetMarkdownEditor();
175
-
176
- return (
177
- <>
178
- <JetMarkdownEditor
179
- mentionTriggers={["@"]}
180
- onChangeMarkdown={(markdown) => save(markdown)}
181
- onMentionChange={({ query }) => search(query)}
182
- placeholder="Write something..."
183
- ref={editor.ref}
184
- />
185
- <Button onPress={editor.toggleBold} title="B" />
186
- </>
187
- );
188
- }
189
- ```
190
-
191
- ### Formatting
192
-
193
- Inline marks — bold, italic, strikethrough, inline code, spoiler, superscript, subscript — toggle over the selection, or arm for the text typed next at a collapsed cursor (`toggleBold()`, `toggleItalic()`, `toggleStrikethrough()`, `toggleCode()`, `toggleSpoiler()`, `toggleSuperscript()`, `toggleSubscript()`).
194
-
195
- Blocks apply per line: `toggleHeading(1-6)`, `toggleBlockQuote()`, `toggleCodeBlock()`, `toggleUnorderedList()`, `toggleOrderedList()`. Enter continues a list, Enter on an empty item exits it, Enter after a heading returns to paragraph, and backspace at the start of a formatted line clears its block first.
196
-
197
- `onChangeState` reports the formatting at the cursor or selection (`isBold`, `headingLevel`, `isUnorderedList`, ...) for toolbar highlighting.
198
-
199
- ### Links & mentions
200
-
201
- `insertLink(url, label?)` links the selection (or inserts a linked label), `removeLink()` strips it. Typing a bare `http(s)://` URL followed by a space emits `onLinkDetected` — call `insertLink` if you want it linkified.
202
-
203
- Mentions start when a `mentionTriggers` character is typed at a word start: `onMentionStart` → `onMentionChange` (with the growing query) → `onMentionEnd`. Call `insertMention(trigger, label, url)` — e.g. `("@", "ali", "users://ali")` — to replace the query with an atomic token that deletes as one unit.
204
-
205
- ### Paste
206
-
207
- Paste never inserts directly. `onPaste` receives `{ text?, images?, preventDefault() }` — images are reported (never auto-inserted) with `url`, `width`, `height`. Unless you call `preventDefault()` synchronously, the pasted text is parsed as markdown and inserted styled.
208
-
209
- ### Everything else
210
-
211
- `getMarkdown()` resolves the current markdown; `focus()`, `blur()`, `setSelection(start, end)`, `setValue(markdown)`, and `insertMarkdown(markdown)` do what they say. Hardware keyboards get Cmd+B / Cmd+I (iOS) and Ctrl+B / Ctrl+I (Android). The editor shares the viewer's `style` / `styles` contract — the `base`/`paragraph` cascade drives the root text and `link.color` drives links. The viewer's `gap` is not applied while editing (a text field flows line to line); drive the editing feel with the text styles themselves.
212
-
213
161
  ## Platform notes & limitations
214
162
 
215
163
  - New Architecture (Fabric) only; React Native 0.86+.
216
164
  - `textDecorationStyle`/`textDecorationColor` render fully on iOS; Android draws plain underline/strikethrough.
217
165
  - `borderCurve: 'continuous'` is iOS-only.
218
166
  - `fontVariant` supports `tabular-nums`, `proportional-nums`, `oldstyle-nums`, `lining-nums`, `small-caps` (font support required).
219
- - `allowFontScaling` (default `true`) scales all text — including `lineHeight` — with the system font size setting on both components.
167
+ - `allowFontScaling` (default `true`) scales all text — including `lineHeight` — with the system font size setting.
220
168
  - Spoilers and inline formatting inside link labels stay literal; spoilers inside table cells are unsupported (the `|` delimiter conflicts).
221
169
  - Code blocks render plain monospace (no syntax highlighting).
222
170
 
@@ -12,7 +12,6 @@
12
12
  #include <vector>
13
13
 
14
14
  #include "core/AstSerializer.h"
15
- #include "core/EditorRuns.h"
16
15
  #include "core/Parser.h"
17
16
  #include "react/JetMarkdownMeasurer.h"
18
17
 
@@ -87,111 +86,6 @@ Java_com_jetmarkdown_JetMarkdownNative_parse(JNIEnv* env, jclass, jbyteArray mar
87
86
  return toByteArray(env, bytes.data(), bytes.size());
88
87
  }
89
88
 
90
- extern "C" JNIEXPORT jbyteArray JNICALL
91
- Java_com_jetmarkdown_JetMarkdownNative_markdownFromEditorContent(
92
- JNIEnv* env,
93
- jclass,
94
- jbyteArray text,
95
- jintArray runs,
96
- jintArray lineBlocks,
97
- jintArray linkRanges,
98
- jbyteArray linkUrls) {
99
- std::vector<jetmarkdown::StyledRun> styledRuns;
100
- if (runs != nullptr) {
101
- const jsize length = env->GetArrayLength(runs);
102
- std::vector<jint> values(static_cast<size_t>(length));
103
- if (length > 0) {
104
- env->GetIntArrayRegion(runs, 0, length, values.data());
105
- }
106
- for (jsize i = 0; i + 2 < length; i += 3) {
107
- styledRuns.push_back(
108
- {static_cast<uint32_t>(values[i]),
109
- static_cast<uint32_t>(values[i + 1]),
110
- static_cast<uint32_t>(values[i + 2])});
111
- }
112
- }
113
- std::vector<jetmarkdown::EditorLine> lines;
114
- if (lineBlocks != nullptr) {
115
- const jsize length = env->GetArrayLength(lineBlocks);
116
- std::vector<jint> values(static_cast<size_t>(length));
117
- if (length > 0) {
118
- env->GetIntArrayRegion(lineBlocks, 0, length, values.data());
119
- }
120
- for (jsize i = 0; i + 1 < length; i += 2) {
121
- lines.push_back(
122
- {static_cast<jetmarkdown::EditorBlockType>(values[i]),
123
- static_cast<uint8_t>(values[i + 1])});
124
- }
125
- }
126
- // Link URLs cross as one newline-joined blob (URLs cannot contain '\n').
127
- std::vector<jetmarkdown::LinkRun> links;
128
- if (linkRanges != nullptr) {
129
- const jsize length = env->GetArrayLength(linkRanges);
130
- std::vector<jint> values(static_cast<size_t>(length));
131
- if (length > 0) {
132
- env->GetIntArrayRegion(linkRanges, 0, length, values.data());
133
- }
134
- const std::string urls = toStdString(env, linkUrls);
135
- size_t urlStart = 0;
136
- for (jsize i = 0; i + 1 < length; i += 2) {
137
- const size_t urlEnd = urls.find('\n', urlStart);
138
- links.push_back(
139
- {static_cast<uint32_t>(values[i]),
140
- static_cast<uint32_t>(values[i + 1]),
141
- urls.substr(urlStart, urlEnd == std::string::npos ? std::string::npos
142
- : urlEnd - urlStart)});
143
- urlStart = urlEnd == std::string::npos ? urls.size() : urlEnd + 1;
144
- }
145
- }
146
- const std::string result = jetmarkdown::markdownFromEditor(
147
- toStdString(env, text), styledRuns, lines, links);
148
- return toByteArray(
149
- env, reinterpret_cast<const uint8_t*>(result.data()), result.size());
150
- }
151
-
152
- extern "C" JNIEXPORT jbyteArray JNICALL
153
- Java_com_jetmarkdown_JetMarkdownNative_editorFromMarkdownContent(
154
- JNIEnv* env,
155
- jclass,
156
- jbyteArray markdown) {
157
- const jetmarkdown::EditorDocument document =
158
- jetmarkdown::editorFromMarkdown(toStdString(env, markdown));
159
- // [int32 runCount][runCount x (start, end, flags)][int32 lineCount]
160
- // [lineCount x (type, level)][utf8 text], little-endian.
161
- std::vector<uint8_t> bytes;
162
- bytes.reserve(
163
- 8 + document.runs.size() * 12 + document.lines.size() * 8 +
164
- document.text.size());
165
- const auto push32 = [&bytes](uint32_t value) {
166
- bytes.push_back(static_cast<uint8_t>(value & 0xFF));
167
- bytes.push_back(static_cast<uint8_t>((value >> 8) & 0xFF));
168
- bytes.push_back(static_cast<uint8_t>((value >> 16) & 0xFF));
169
- bytes.push_back(static_cast<uint8_t>((value >> 24) & 0xFF));
170
- };
171
- push32(static_cast<uint32_t>(document.runs.size()));
172
- for (const jetmarkdown::StyledRun& run : document.runs) {
173
- push32(run.start);
174
- push32(run.end);
175
- push32(run.flags);
176
- }
177
- push32(static_cast<uint32_t>(document.lines.size()));
178
- for (const jetmarkdown::EditorLine& line : document.lines) {
179
- push32(static_cast<uint32_t>(line.type));
180
- push32(line.level);
181
- }
182
- push32(static_cast<uint32_t>(document.links.size()));
183
- for (const jetmarkdown::LinkRun& link : document.links) {
184
- push32(link.start);
185
- push32(link.end);
186
- push32(static_cast<uint32_t>(link.url.size()));
187
- }
188
- for (const jetmarkdown::LinkRun& link : document.links) {
189
- bytes.insert(bytes.end(), link.url.begin(), link.url.end());
190
- }
191
- bytes.insert(bytes.end(), document.text.begin(), document.text.end());
192
- return toByteArray(env, bytes.data(), bytes.size());
193
- }
194
-
195
89
  extern "C" JNIEXPORT void JNICALL
196
90
  Java_com_jetmarkdown_JetMarkdownNative_installMeasurer(
197
91
  JNIEnv* env,
@@ -29,86 +29,7 @@ object JetMarkdownNative {
29
29
  }
30
30
 
31
31
 
32
- /** Decoded editor content: text, inline-mark runs, line blocks, links. */
33
- class EditorContent(
34
- val text: String,
35
- /** Flat `[start, end, flags]` triples in UTF-16 offsets. */
36
- val runs: IntArray,
37
- /** Flat `[type, level]` pairs, one per text line. */
38
- val lineBlocks: IntArray,
39
- /** Flat `[start, end]` pairs, aligned with [linkUrls]. */
40
- val linkRanges: IntArray,
41
- val linkUrls: List<String>,
42
- )
43
-
44
- /**
45
- * Editor: markdown from text + inline-mark runs + per-line blocks +
46
- * links. Runs are flat `[start, end, flags]` triples in UTF-16 offsets
47
- * (Spannable indices); lineBlocks are `[type, level]` pairs per line;
48
- * links are `[start, end]` pairs with URLs joined by '\n'.
49
- */
50
- fun markdownFromEditor(
51
- text: String,
52
- runs: IntArray,
53
- lineBlocks: IntArray,
54
- linkRanges: IntArray = IntArray(0),
55
- linkUrls: List<String> = emptyList(),
56
- ): String {
57
- return markdownFromEditorContent(
58
- text.toByteArray(Charsets.UTF_8),
59
- runs,
60
- lineBlocks,
61
- linkRanges,
62
- linkUrls.joinToString("\n").toByteArray(Charsets.UTF_8),
63
- ).toString(Charsets.UTF_8)
64
- }
65
-
66
- /**
67
- * Editor: markdown parsed into editor content. The native payload is
68
- * `[int32 runCount][triples][int32 lineCount][pairs][int32 linkCount]
69
- * [(start, end, urlLen) triples][url bytes][utf8 text]`, little-endian.
70
- */
71
- fun editorFromMarkdown(markdown: String): EditorContent {
72
- val bytes = editorFromMarkdownContent(markdown.toByteArray(Charsets.UTF_8))
73
- val buffer = java.nio.ByteBuffer.wrap(bytes).order(java.nio.ByteOrder.LITTLE_ENDIAN)
74
- val runs = IntArray(buffer.int * 3)
75
- for (i in runs.indices) {
76
- runs[i] = buffer.int
77
- }
78
- val lineBlocks = IntArray(buffer.int * 2)
79
- for (i in lineBlocks.indices) {
80
- lineBlocks[i] = buffer.int
81
- }
82
- val linkCount = buffer.int
83
- val linkRanges = IntArray(linkCount * 2)
84
- val urlLengths = IntArray(linkCount)
85
- for (i in 0 until linkCount) {
86
- linkRanges[i * 2] = buffer.int
87
- linkRanges[i * 2 + 1] = buffer.int
88
- urlLengths[i] = buffer.int
89
- }
90
- val linkUrls = ArrayList<String>(linkCount)
91
- for (i in 0 until linkCount) {
92
- val urlBytes = ByteArray(urlLengths[i])
93
- buffer.get(urlBytes)
94
- linkUrls.add(urlBytes.toString(Charsets.UTF_8))
95
- }
96
- val text = ByteArray(buffer.remaining())
97
- buffer.get(text)
98
- return EditorContent(text.toString(Charsets.UTF_8), runs, lineBlocks, linkRanges, linkUrls)
99
- }
100
-
101
32
  @JvmStatic private external fun parse(markdown: ByteArray): ByteArray
102
33
 
103
- @JvmStatic private external fun markdownFromEditorContent(
104
- text: ByteArray,
105
- runs: IntArray,
106
- lineBlocks: IntArray,
107
- linkRanges: IntArray,
108
- linkUrls: ByteArray,
109
- ): ByteArray
110
-
111
- @JvmStatic private external fun editorFromMarkdownContent(markdown: ByteArray): ByteArray
112
-
113
34
  @JvmStatic private external fun installMeasurer(measurer: MarkdownMeasurer)
114
35
  }
@@ -5,7 +5,6 @@ import com.facebook.react.bridge.NativeModule
5
5
  import com.facebook.react.bridge.ReactApplicationContext
6
6
  import com.facebook.react.module.model.ReactModuleInfoProvider
7
7
  import com.facebook.react.uimanager.ViewManager
8
- import com.jetmarkdown.editor.JetMarkdownEditorManager
9
8
 
10
9
  class JetMarkdownViewPackage : BaseReactPackage() {
11
10
  override fun createViewManagers(reactContext: ReactApplicationContext): List<ViewManager<*, *>> {
@@ -13,7 +12,7 @@ class JetMarkdownViewPackage : BaseReactPackage() {
13
12
  // font/color resolution must work from the very first measure. The view
14
13
  // managers re-install with the themed context on view creation.
15
14
  com.jetmarkdown.style.PlatformColorResolver.install(reactContext)
16
- return listOf(JetMarkdownViewManager(), JetMarkdownEditorManager())
15
+ return listOf(JetMarkdownViewManager())
17
16
  }
18
17
 
19
18
  override fun getModule(name: String, reactContext: ReactApplicationContext): NativeModule? = null
@@ -1,26 +1,15 @@
1
1
  package com.jetmarkdown.render.spans
2
2
 
3
3
  import android.graphics.Paint
4
- import android.text.TextPaint
5
4
  import android.text.style.LineHeightSpan
6
- import android.text.style.MetricAffectingSpan
7
5
  import kotlin.math.ceil
8
6
  import kotlin.math.floor
9
7
 
10
8
  /**
11
9
  * React Native's lineHeight semantics: the line box is exactly [heightPx]
12
- * tall with glyphs centered (mirrors RN's CustomLineHeightSpan). Extends
13
- * MetricAffectingSpan (a no-op there) so DynamicLayout — the editor —
14
- * reflows when the span is attached; plain LineHeightSpan is not an
15
- * UpdateLayout span.
10
+ * tall with glyphs centered (mirrors RN's CustomLineHeightSpan).
16
11
  */
17
- open class MarkdownLineHeightSpan(private val heightPx: Int) :
18
- MetricAffectingSpan(),
19
- LineHeightSpan {
20
- override fun updateMeasureState(paint: TextPaint) = Unit
21
-
22
- override fun updateDrawState(paint: TextPaint) = Unit
23
-
12
+ class MarkdownLineHeightSpan(private val heightPx: Int) : LineHeightSpan {
24
13
  override fun chooseHeight(
25
14
  text: CharSequence,
26
15
  start: Int,
@@ -7,7 +7,6 @@
7
7
 
8
8
  #include <react/renderer/core/ConcreteComponentDescriptor.h>
9
9
 
10
- #include "../../../../../JetMarkdownEditorShadowNode.h"
11
10
  #include "../../../../../JetMarkdownShadowNode.h"
12
11
 
13
12
  namespace facebook::react {
@@ -15,7 +14,4 @@ namespace facebook::react {
15
14
  using JetMarkdownViewComponentDescriptor =
16
15
  ConcreteComponentDescriptor<JetMarkdownShadowNode>;
17
16
 
18
- using JetMarkdownEditorComponentDescriptor =
19
- ConcreteComponentDescriptor<JetMarkdownEditorShadowNode>;
20
-
21
17
  } // namespace facebook::react